namespace Yaaf.WP7.NativeAccess.IO
{
    using System;
    using System.Collections.Generic;
    using System.IO;

    using Yaaf.Wp7.AdvancedExplorer;
    using Yaaf.WP7.NativeAccess.Helper;
    using Yaaf.WP7.NativeAccess.IO.Internals.AllDevices;
    using Yaaf.WP7.NativeAccess.IO.Internals.HTC;

    public interface IFileSystemAccess
    {
        Stream OpenFile(string path, FileMode mode, FileAccess access);

        bool ExistsFile(string path);

        void MoveFile(string path, string dest, bool overwrite);

        void DeleteFile(string path);

        void CopyFile(string source, string dest, bool overwrite);

        long GetFileSize(string fullName);

        bool ExistsDirectory(string fullName);

        PathInformation GetPathInformation(string path);

        IEnumerable<FileSystemEntryStruct> EnumerateFileSystemEntries(string path, bool includeFiles, bool includeDirectories, string search, bool fullPath);

        void CreateDirectory(string fullName);

        void DeleteDirectory(string fullName, bool recursive);

        void ExecuteFile(string fullName);
    }

    public struct FileSystemEntryStruct
    {
        public string Name;
        public long Size;

        public bool? IsFile;

        public FileSystemEntryStruct(string name)
        {
            Name = name;
            IsFile = null;
            Size = -1;
        }

        public FileSystemEntryStruct(string name, bool isFile, long size = -1)
        {
            Name = name;
            IsFile = isFile;
            Size = -1;
        }
    }

    public class FileSystemAccess : AccessManager<IFileSystemAccess>
    {
        public static bool UseLimitedAccess
        {
            get
            {
                return Access.GetType() == typeof(LimitedFileSystemAccess);
            }
            set
            {
                if (value == UseLimitedAccess)
                {
                     return;
                }

                if (value)
                {
                    SwitchAccess(new LimitedFileSystemAccess());
                    Logger.Instance.WriteLine("Switching to LimitedFileSystemAccess on {0}", DeviceSwitcher.DeviceType);
                }
                else
                {
                    Instance.Initialize();
                    WriteLog();
                }
            }
        }

        private static void WriteLog()
        {
            if (IsAvailable)
            {
                Wp7.AdvancedExplorer.Logger.Instance.WriteLine("Using following FileSystemAccess: {0}, Device: {1}", Access.GetType().FullName, DeviceSwitcher.DeviceType);
            }
            else
            {
                Wp7.AdvancedExplorer.Logger.Instance.WriteLine(
                    "Registry Access not available! (Device: {0})", DeviceSwitcher.DeviceType);
            }
        }


        protected override IFileSystemAccess GetAccessFromDevice(DeviceManufacturer manufacturer)
        {
            IFileSystemAccess access = null;
            switch (manufacturer)
            {
                //case DeviceManufacturer.LG:
                //case DeviceManufacturer.Samsung:
                //case DeviceManufacturer.ASUS:
                //case DeviceManufacturer.Dell:
                //case DeviceManufacturer.Unknown:

                case DeviceManufacturer.HTC:
                    access = new HtcFileSystemAccess();
                    break;
                default:
                    try
                    {
                        access = new Internals.AllDevices.FileSystemAccess();
                    }
                    catch (RegisterComException e)
                    {
                        Logger.Instance.WriteLine("Ignoring RegisterComException and switching to LimitedAccess (Details: {0})", e);
                        access = new LimitedFileSystemAccess();
                    }
                    break;
            }

            return access;
        }

        private static bool isInitialized = false;
        public static new void Initialize()
        {
            if (isInitialized)
            {
                return;
            }
            isInitialized = true;
            Instance = new FileSystemAccess();
            Instance.Initialize();
            WriteLog();
        }

        private static void CheckAccess()
        {
            if (!IsAvailable || Access == null)
            {
                throw new UnauthorizedAccessException("No Access on the Filesystem!");
            }
        }

        public static Stream OpenFile(string path, FileMode mode, FileAccess access)
        {
            CheckAccess();
            return Access.OpenFile(path, mode, access);
        }

        public static bool ExistsFile(string path)
        {
            CheckAccess();
            return Access.ExistsFile(path);
        }

        public static void MoveFile(string path, string dest, bool overwrite)
        {
            CheckAccess();
            Access.MoveFile(path, dest, overwrite);
        }

        public static void DeleteFile(string path)
        {
            CheckAccess();
            Access.DeleteFile(path);
        }

        public static void CopyFile(string source, string dest, bool overwrite)
        {
            CheckAccess();
            Access.CopyFile(source, dest, overwrite);
        }

        public static long GetFileSize(string fullName)
        {
            CheckAccess();
            return Access.GetFileSize(fullName);
        }

        public static bool ExistsDirectory(string fullName)
        {
            CheckAccess();
            return Access.ExistsDirectory(fullName);
        }

        public static PathInformation GetPathInformation(string path)
        {
            CheckAccess();
            return Access.GetPathInformation(path);
        }

        public static IEnumerable<FileSystemEntryStruct> EnumerateFileSystemEntries(string path, bool includeFiles, bool includeDirectories, string search, bool fullPath)
        {
            CheckAccess();
            return Access.EnumerateFileSystemEntries(path, includeFiles, includeDirectories, search, fullPath);
        }

        public static void CreateDirectory(string fullName)
        {
            CheckAccess();
            Access.CreateDirectory(fullName);
        }

        public static void DeleteDirectory(string fullName, bool recursive)
        {
            CheckAccess();
            Access.DeleteDirectory(fullName, recursive);
        }

        public static void ExecuteFile(string fullName)
        {
            CheckAccess();
            Access.ExecuteFile(fullName);
        }
    }
}